import { Query, Mutation, Args, Resolver } from '@nestjs/graphql';
import { Type, UseGuards } from '@nestjs/common';
import { BaseService } from './baseService';
import { GraphQLBigInt } from 'graphql-scalars';
import { JwtAuthGuard } from 'src/system/auth/guard/jwt-auth.guard';
import { IBaseInputDto } from './baseDtoType';

/**
 * 公共的基础的Resolver
 * @param classRef 实体类
 * @param dtoTypes DTO输入{
 *   createDto: Type<ICreateInputDto>,创建Dto
 *   updateDto: Type<IUpdateInputDto>, 更新Dto
 *   searchDto: Type<ISearchInputDto>, 搜索Dto
 *   pageResopneDto: Type<IPageResopneDto>, 分页响应Dto
 *   inputPageDto: Type<IInputPageDto>, 分页查询Dto
 * }
 * @param description 
 * @returns 
 */
export function BaseResolver<T, DT extends IBaseInputDto<any, any, any, any, any>>
  (classRef: Type<T>, dtoTypes: DT, description = ''
  ): any {
  @Resolver({ isAbstract: true })
  abstract class AbstractBaseResolver {
    protected constructor(protected readonly service: BaseService<T>) {
      description = description ?? `${classRef.name}`;
    }

    /**
     * 查询所有
     */
    @Query(() => [classRef], { name: `findAll${classRef.name}s`, description: `查询所有${description}` })
    @UseGuards(JwtAuthGuard)
    async findAll(): Promise<T[]> {
      return this.service.findAll();
    }

    /**
     * 根据Id查询
     */
    @Query(() => classRef, { name: `find${classRef.name}ById`, nullable: true, description: `根据Id查询${description}` })
    @UseGuards(JwtAuthGuard)
    async findbyId(@Args('id', { type: () => GraphQLBigInt }) id: number): Promise<T | null> {
      return this.service.findById(id);
    }

    /**
     * 根据条件查询
     * @param queryType 查询类型
     * @returns List<T>
     * @description 仅返回List
     */
    @Query(() => [classRef], { name: `find${classRef.name}WhereList`, nullable: true, description: `根据Json查询${description}List` })
    @UseGuards(JwtAuthGuard)
    async findWhere(@Args('jsonQuery', { type: () => dtoTypes.searchDto }) queryType: InstanceType<DT['searchDto']>): Promise<T[] | null> {
      return this.service.findWhereList(queryType);
    }

    /**
     * 根据条件查询
     * @param queryType 查询类型
     * @returns T
     * @description 仅返回一条数据
     */
    @Query(() => classRef, { name: `find${classRef.name}WhereOne`, nullable: true, description: `根据Json查询${description}One` })
    @UseGuards(JwtAuthGuard)
    async findWhereOne(@Args('jsonQuery', { type: () => dtoTypes.searchDto }) jsonQuery: InstanceType<DT['searchDto']>): Promise<T[] | null> {
      return this.service.findWhereList(jsonQuery);
    }

    /**
     * 分页查询
     * @param pageInput 分页查询参数
     * @returns 分页响应Dto
     * @description 分页查询
     * @deprecated 请使用findPage
     * @see findPage
     */
    @Query(() => dtoTypes.pageResopneDto, { name: `find${classRef.name}Page`, description: `分页查询${description}` })
    findPage(@Args('pageInput', { type: () => dtoTypes.pageInputDto }) pageInput: InstanceType<DT['pageInputDto']>):
      Promise<any> {
      return new Promise(async (resolve, _reject) => {
        const input = (pageInput as any)
        resolve({
          page: input.page,
          limit: input.limit,
          total: await this.service.count(input.query),
          items: await this.service.findPage(input)
        });
      });
    }

    /**
     * 创建
     * @param createInput 创建Dto
     * @returns T
     */
    @Mutation(() => classRef, { name: `create${classRef.name}`, description: `创建${description}` })
    @UseGuards(JwtAuthGuard)
    async create(@Args(`create${classRef.name}Input`, { type: () => dtoTypes.createDto }) createInput: InstanceType<DT['createDto']>) {
      return this.service.create(createInput);
    }

    /**
     * 更新
     * @param id id
     * @param updateInput 更新的Dto
     * @returns 
     */
    @Mutation(() => classRef, { name: `update${classRef.name}`, description: `修改${description}` })
    @UseGuards(JwtAuthGuard)
    async update(@Args('id', { type: () => GraphQLBigInt }) id: number,
      @Args(`update${classRef.name}Input`, { type: () => dtoTypes.updateDto }) updateInput: InstanceType<DT['updateDto']>): Promise<T | null> {
      return this.service.update(id, updateInput);
    }

    /**
     * 软删除
     * @param id id
     * @returns T
     * @description 软删除
     * @deprecated 请使用softDelete
     * @see softDelete
     */
    @Mutation(() => classRef, { name: `softDelete${classRef.name}`, description: `软删除${description}` })
    @UseGuards(JwtAuthGuard)
    async softDelete(@Args('id', { type: () => GraphQLBigInt }) id: number): Promise<T | null> {
      return this.service.softDelete(id);
    }

    /**
     * 真删除
     * @param id id
     * @returns T
     * @description 真删除
     * @deprecated 请使用hardDelete
     * @see hardDelete
     */
    @Mutation(() => classRef, { name: `hardDelete${classRef.name}`, description: `真删除${description}` })
    @UseGuards(JwtAuthGuard)
    async hardDelete(@Args('id', { type: () => GraphQLBigInt }) id: number): Promise<T | null> {
      return this.service.hardDelete(id);
    }
  }

  return AbstractBaseResolver;
}
